package test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;

public class SelfJStack {
	public static void main(String[] args) throws Exception {
		RuntimeMXBean runtimebean = ManagementFactory.getRuntimeMXBean();
		String pid = getPid(runtimebean);
		System.out.println(pid);
		ThreadGroup group = new ThreadGroup("Priority Threads");
		boolean[] done = new boolean[1];
//		startThreads(group, done, 1);
//		startU(group, done);
		Thread.sleep(1000);
		String jstack = System.getProperty("java.home") + "/../bin/jstack";
		Process process = new ProcessBuilder(jstack, pid).redirectErrorStream(true).start();
		BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
		try {
			String line;
			while((line = reader.readLine()) != null) {
				System.out.println(line);
			}
		} finally {
			reader.close();
		}
		if (Boolean.getBoolean("pause")) System.in.read();
		notifyDone(done);
	}

	static String getPid(RuntimeMXBean runtimebean) {
		String vmname = runtimebean.getName();
		int i = vmname.indexOf('@');
		if (i != -1) {
			vmname = vmname.substring(0, i);
		}
		return vmname;
	}

	static void startThreads(ThreadGroup group, boolean[] done, int level) {
		for (int priority = Thread.MIN_PRIORITY; priority <= Thread.MAX_PRIORITY; ++priority) {
			new T(group, done, priority, level).start();
		}
	}

	static void startU(ThreadGroup group, boolean[] done) {
		Thread t = new U(group, done);
		t.start();
		for (int priority = Thread.MIN_PRIORITY; priority <= Thread.MAX_PRIORITY; ++priority) {
			t.setPriority(priority);
		}
	}

	static void notifyDone(boolean[] done) {
		synchronized (done) {
			done[0] = true;
			done.notifyAll();
		}
	}

	static void waitTillDone(boolean[] done) {
		synchronized (done) {
			while (!done[0]) {
				try {
					done.wait();
				} catch (InterruptedException exc) {
					// ignore
				}
			}
		}
	}

	static class T extends Thread {
		private final boolean[] _done;
		private final int _level;

		T(ThreadGroup group, boolean[] done, int priority, int level) {
			super(group, Thread.currentThread().getName() + "->" + priority);
			_done = done;
			_level = level;
			setPriority(priority);
		}

		public void run() {
			if (_level > 0) {
				int l = _level - 1;
				startThreads(getThreadGroup(), _done, l);
			}
			waitTillDone(_done);
		}
	}

	static class U extends Thread {
		private final boolean[] _done;

		U(ThreadGroup group, boolean[] done) {
			super(group, Thread.currentThread().getName() + "->U");
			_done = done;
		}

		public void run() {
			waitTillDone(_done);
		}
	}
}
